#ifndef __ILIB_TP_PBNC_H_20120430_H__
#define __ILIB_TP_PBNC_H_20120430_H__

#include "iOTCPConnection.h"
#include "../util/h/iMsgDB.h"
#include "../util/h/iLogger.h"
class iPBNConnection : public iOTCPConnection
{
public:
	iPBNConnection(iSocket* so, iConnection* prvd, iAllocator* alloc);

	// override iConnection
	virtual void on_connect_confirm();
	virtual void on_data_indication(iMsgDB* mdb);

	// override iMsg::iSink
	int on_message(iMsgID msg, void* param);

	// override iTPConnection
	virtual int32_t connect_request(iMsgDB* request,  iTPConnection::iSink* sink);
	virtual int32_t connect_response(iMsgDB* response,iTPConnection::iSink* sink);
    virtual int32_t get_option(TP_OPTION, void* optval, int32_t optlen);

	// override iOTCPConnection
	virtual int32_t send_data(iMsgDB* data);

protected:

	class Packer {
	public:
		struct {
			uint16_t length;
			uint16_t reserved;
			struct {
				uint16_t reserved; 
				uint16_t version;
			} hardcore;
		} header;

		inline Packer() : package(NULL), m_lack_len(sizeof(header)), m_wait_header(true) {
		}
		inline ~Packer() {
			if(package)
				package->release();
			package = NULL;
		}
		inline void pack(iMsgDB* mdb) {
			if(package == NULL) {
				header.hardcore.version = 1;
				header.length = mdb->get_total_data_length();
				package = iMsgDB::new_instance(NULL, 64);
				package->write((uint8_t*)&header, sizeof(header));
			}
			package->append(mdb);
		}
		inline iMsgDB* extract(iMsgDB* mdb) {
            if(mdb)
            {
                m_lack_len -= mdb->get_total_data_length();
                m_lack_len = m_lack_len<0 ? 0:m_lack_len;
            }
            if(package==NULL)
                package = mdb;
            else
                package->append(mdb);

            if(m_lack_len == 0 && m_wait_header)
            {
				package->read((uint8_t*)&header, sizeof(header));
                m_lack_len = header.length;
                DEBUG("required length="<<m_lack_len);
                m_lack_len -= package->get_total_data_length();
                m_lack_len = m_lack_len<0 ? 0:m_lack_len;
                m_wait_header = false;
            }

            if(m_lack_len == 0)
            {
                iMsgDB* out = fit();
                m_wait_header = out!=NULL;
                m_lack_len = m_wait_header ? sizeof(header):m_lack_len;
                if(package)
                {
                    m_lack_len -= package->get_total_data_length();
                    m_lack_len = m_lack_len<0 ? 0:m_lack_len;
                }
                return out;
            }

            return NULL;
		}
		inline iMsgDB* fit() {
			iMsgDB* part2 = NULL;
			iMsgDB* part1 = package->clips(header.length, part2);
			if(part1)
				package = part2;
			return part1;
		}

		iMsgDB*     package;
        int32_t     m_lack_len;
        bool        m_wait_header;
	};
	Packer	    m_packer;
};

#endif  //__ILIB_TP_PBNC_H_20120430_H__
